package com.alibaba.citrus.cr.mn.order.center.facade.function.convert;

import ma.glasnost.orika.Converter;
import ma.glasnost.orika.MapperFacade;
import ma.glasnost.orika.MapperFactory;
import ma.glasnost.orika.impl.DefaultMapperFactory;
import ma.glasnost.orika.metadata.ClassMapBuilder;
import ma.glasnost.orika.metadata.Type;
import ma.glasnost.orika.metadata.TypeBuilder;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;

import java.util.*;

public class BeanConverter {

    private static final MapperFactory MAPPER_FACTORY;
    private static final MapperFacade MAPPER_FACADE;

    private static final MapperFactory MAPPER_NULL_FACTORY;
    private static final MapperFacade MAPPER_NULL_FACADE;

    static {
        DefaultMapperFactory.MapperFactoryBuilder<DefaultMapperFactory, DefaultMapperFactory.Builder> builder
                = new DefaultMapperFactory.Builder();
        MAPPER_FACTORY = builder.build();
        MAPPER_FACADE = MAPPER_FACTORY.getMapperFacade();
        //非空转换
        DefaultMapperFactory.MapperFactoryBuilder<DefaultMapperFactory, DefaultMapperFactory.Builder> nullBuilder
                = new DefaultMapperFactory.Builder().mapNulls(false);
        MAPPER_NULL_FACTORY = nullBuilder.build();

        MAPPER_NULL_FACADE = MAPPER_NULL_FACTORY.getMapperFacade();
    }

    public static <S, T> T convert(S origin, Class<T> destClz) {
        if (origin == null || destClz == null) {
            return null;
        }
        return MAPPER_FACADE.map(origin, destClz);
    }

    public static <S, D> D convert(S origin, D dest) {
        if (origin == null || dest == null) {
            return null;
        }
        MAPPER_FACADE.map(origin, dest);
        return dest;
    }

    public static <S, T> T convert(S origin, Type<S> sourceType, Type<T> desType) {
        // 泛型转换
        if (origin == null || sourceType == null || desType == null) {
            return null;
        }
        return MAPPER_FACADE.map(origin, sourceType, desType);
    }

    public static <S, T> T convert(S origin, Class<T> destClz, Map<String, String> fieldsMap) {
        if (origin == null || destClz == null) {
            return null;
        }

        if (fieldsMap == null || fieldsMap.size() == 0) {
            return null;
        }

        MapperFacade mapperFacade = getMapperFacade(origin.getClass(), destClz, fieldsMap, null, null);
        return mapperFacade.map(origin, destClz);
    }

    public static <S, D> D convert(S origin, D dest, Map<String, String> fieldsMap) {
        if (origin == null || dest == null) {
            return null;
        }

        if (fieldsMap == null || fieldsMap.size() == 0) {
            return null;
        }

        MapperFacade mapperFacade = getMapperFacade(origin.getClass(), dest.getClass(), fieldsMap, null, null);
        mapperFacade.map(origin, dest);
        return dest;
    }

    public static <S, T> T convertSupportDateString(S origin, Class<T> destClz, Map<String, String> fieldsMap,
                                                    Map<String, String> customConverterFieldsMap) {

        if (origin == null || destClz == null) {
            return null;
        }

        if (fieldsMap == null || fieldsMap.size() == 0) {
            return null;
        }

        if (customConverterFieldsMap == null || customConverterFieldsMap.size() == 0) {
            return null;
        }

        // 注册自定义转换器
        String customConverterName = "datetimeStringConverter";
        MapperFacade mapperFacade = getMapperFacade(origin.getClass(), destClz, fieldsMap, customConverterName,
                customConverterFieldsMap);
        return mapperFacade.map(origin, destClz);

    }

    public static <S, T> T convertSupportDateString(S origin, Class<T> destClz, Map<String, String> fieldsMap,
                                                    Map<String, String> customConverterFieldsMap, Converter converter) {

        if (origin == null || destClz == null) {
            return null;
        }

        // 注册自定义转换器
        String customConverterName = "datetimeStringConverter";
        MapperFacade mapperFacade = getMapperFacade(origin.getClass(), destClz, fieldsMap, customConverterName,
                customConverterFieldsMap, converter);
        return mapperFacade.map(origin, destClz);

    }

    public static <S, T> List<T> convert(List<S> originList, Class<T> destClz) {
        if (CollectionUtils.isEmpty(originList) || destClz == null) {
            return new ArrayList<>(0);
        }
        return MAPPER_FACADE.mapAsList(originList, destClz);
    }

    public static <S, T> List<T> convert(List<S> originList, Class<T> destClz, Map<String, String> fieldsMap) {
        if (CollectionUtils.isEmpty(originList) || destClz == null) {
            return new ArrayList<>(0);
        }

        if (fieldsMap == null || fieldsMap.size() == 0) {
            return new ArrayList<>(0);
        }

        MapperFacade mapperFacade = getMapperFacade(originList.get(0).getClass(), destClz, fieldsMap, null, null);
        return mapperFacade.mapAsList(originList, destClz);
    }

    public static <S, T> List<T> convertSupportDateString(
            List<S> originList, Class<T> destClz, Map<String, String> fieldsMap,
            Map<String, String> customConverterFieldsMap) {

        if (CollectionUtils.isEmpty(originList) || destClz == null) {
            return new ArrayList<>(0);
        }

        if (fieldsMap == null || fieldsMap.size() == 0) {
            return new ArrayList<>(0);
        }

        if (customConverterFieldsMap == null || customConverterFieldsMap.size() == 0) {
            return null;
        }

        // 注册自定义转换器
        String customConverterName = "datetimeStringConverter";
        MapperFacade mapperFacade = getMapperFacade(originList.get(0).getClass(), destClz, fieldsMap,
                customConverterName, customConverterFieldsMap);
        return mapperFacade.mapAsList(originList, destClz);
    }

    public static <S, T> List<T> convertSupportDateString(
            List<S> originList, Class<T> destClz, Map<String, String> fieldsMap,
            Map<String, String> customConverterFieldsMap, Converter converter) {

        if (CollectionUtils.isEmpty(originList) || destClz == null) {
            return new ArrayList<>(0);
        }

        // 注册自定义转换器
        String customConverterName = "datetimeStringConverter";
        MapperFacade mapperFacade = getMapperFacade(originList.get(0).getClass(), destClz, fieldsMap,
                customConverterName, customConverterFieldsMap, converter);
        return mapperFacade.mapAsList(originList, destClz);
    }

    public static <S, T> Set<T> convert(Set<S> originSet, Class<T> destClz) {
        if (CollectionUtils.isEmpty(originSet) || destClz == null) {
            return new HashSet<>(0);
        }
        return MAPPER_FACADE.mapAsSet(originSet, destClz);
    }

    public static <Sk, Sv, Dk, Dv> Map<Dk, Dv> convert(Map<Sk, Sv> originMap, Type<? extends Map<Dk, Dv>> destMapType) {
        if (MapUtils.isEmpty(originMap) || destMapType == null) {
            return new HashMap<>(0);
        }
        return MAPPER_FACADE.mapAsMap(originMap, new TypeBuilder<Map<Sk, Sv>>() {
        }.build(), destMapType);
    }

    private static <S, T> MapperFacade getMapperFacade(Class<S> sourceClass, Class<T> toClass,
                                                       Map<String, String> configMap, String customConverterName, Map<String, String> customConverterFieldsMap) {
        MapperFactory factory = new DefaultMapperFactory.Builder().build();
        ClassMapBuilder classMapBuilder = factory.classMap(sourceClass, toClass);
        if (configMap != null && configMap.size() > 0) {
            configMap.forEach(classMapBuilder::field);
        }

        if (customConverterFieldsMap != null && customConverterFieldsMap.size() > 0 && StringUtils.isNotBlank(
                customConverterName)) {
            factory.getConverterFactory()
                    .registerConverter(customConverterName, DatetimeStringConverter.getInstance());

            customConverterFieldsMap.forEach((key, value) ->
                    classMapBuilder.fieldMap(key, value).converter(customConverterName).add());
        }
        classMapBuilder.byDefault().register();
        return factory.getMapperFacade();
    }

    private static <S, T> MapperFacade getMapperFacade(Class<S> sourceClass, Class<T> toClass,
                                                       Map<String, String> configMap, String customConverterName,
                                                       Map<String, String> customConverterFieldsMap,
                                                       Converter converter) {
        MapperFactory factory = new DefaultMapperFactory.Builder().build();
        ClassMapBuilder classMapBuilder = factory.classMap(sourceClass, toClass);
        if (MapUtils.isNotEmpty(configMap)) {
            configMap.forEach(classMapBuilder::field);
        }

        if (StringUtils.isNotBlank(customConverterName)) {
            factory.getConverterFactory()
                    .registerConverter(customConverterName, converter);
            if (MapUtils.isNotEmpty(customConverterFieldsMap)) {
                customConverterFieldsMap.forEach((key, value) ->
                        classMapBuilder.fieldMap(key, value).converter(customConverterName).add());
            }
        }

        classMapBuilder.byDefault().register();
        return factory.getMapperFacade();
    }

    public static <S, D> D convertWithoutNull(S origin, D dest) {
        if (origin == null || dest == null) {
            return null;
        }
        MAPPER_NULL_FACADE.map(origin, dest);
        return dest;
    }
}
